package com.panopset.sf.apps.blackjack;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.List;

import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;

import com.panopset.Util;
import com.panopset.compat.RezIO;
import com.panopset.compat.Strings;
import com.panopset.game.DollarConverter;
import com.panopset.game.blackjack.BlackjackConfig;
import com.panopset.game.blackjack.BlackjackGame;
import com.panopset.game.blackjack.ConfigDft;
import com.panopset.game.blackjack.CountingSystems;
import com.panopset.game.blackjack.ScreenSizer;
import com.panopset.refactorsf.PanCheckBox;
import com.panopset.sf.FontManager;
import com.panopset.sf.PanTextField;
import com.panopset.sf.TitledTextArea;
import com.panopset.sf.Windoc;

public class BlackjackSwingConfig implements BlackjackConfig {

    public final Windoc w;

    public BlackjackSwingConfig(final Windoc windoc) {
        w = windoc;
    }

    @Override
    public int getSeats() {
        int rtn = 1;
        try {
            rtn = Integer.parseInt(getSeatsTF().getValue());
        } catch (NumberFormatException ex) {
            Util.log(ex);
        }
        if (rtn < 1) {
            rtn = 1;
        }
        return rtn;
    }

    @Override
    public int getDecks() {
        int rtn = 6;
        try {
            rtn = Integer.parseInt(getDecksTF().getText());
        } catch (NumberFormatException ex) {
            Util.log(ex);
        }
        if (rtn < 1) {
            rtn = 6;
        }
        return rtn;
    }

    @Override
    public int getWagerIncrement() {
        int rtn = ConfigDft.DEFAULT_INITIAL_WAGER;
        try {
            rtn = new DollarConverter().str2long(getIncrTF().getText())
                    .intValue();
        } catch (NumberFormatException ex) {
            Util.log(getIncrTF().getText());
            Util.log(ex);
        }
        if (rtn < 1) {
            rtn = ConfigDft.DEFAULT_INITIAL_WAGER;
        }
        return rtn;
    }

    @Override
    public int getLargeBet() {
        int rtn = ConfigDft.DEFAULT_LARGE_BET;
        try {
            rtn = new DollarConverter().str2long(getLargeBetTF().getText())
                    .intValue();
        } catch (NumberFormatException ex) {
            Util.log(ex);
        }
        if (rtn < 1) {
            rtn = ConfigDft.DEFAULT_LARGE_BET;
        }
        return rtn;
    }

    @Override
    public int getTargetStake() {
        int rtn = ConfigDft.DEFAULT_TARGET_STAKE;
        try {
            rtn = new DollarConverter().str2long(getTargetStakeTF().getText())
                    .intValue();
        } catch (NumberFormatException ex) {
            Util.log(ex);
        }
        if (rtn < 1) {
            rtn = ConfigDft.DEFAULT_TARGET_STAKE;
        }
        return rtn;
    }

    @Override
    public String getRawReloadAmountFromConfig() {
        return getStakeTF().getText();
    }

    private TitledTextArea bs;

    private TitledTextArea getBasicStrategyTA() {
        if (bs == null) {
            String dft = "";
            try {
                dft = RezIO.loadTextFromResource(

                ConfigDft.DEFAULT_STRATEGY_RSRC, this.getClass());
            } catch (IOException e) {
                Util.log(e);
            }
            bs = w.cf.createTitledTextArea(w, Util.x("Basic Strategy"),
                    Util.x("Basic strategy for Blackjack"), dft, "basic");
        }
        return bs;
    }

    @Override
    public List<String> getStrategyData() {
        return Strings.getLines(getBasicStrategyTA().getText());
    }

    private PanTextField seatsTF;

    PanTextField getSeatsTF() {
        if (seatsTF == null) {
            seatsTF = w.cf.createTitledField(w, 10, Util.x("Seats"),
                    Util.x("Number of players."), "1", "seats");
        }
        return seatsTF;
    }

    private PanTextField lbTF;

    PanTextField getLargeBetTF() {
        if (lbTF == null) {
            lbTF = w.cf.createTitledField(w, 10, Util.x("Large Bet"),
                    Util.x("Large Bet (automatic mode only)."),
                    new DollarConverter().int2str(ConfigDft.DEFAULT_LARGE_BET),
                    "lgbet");
        }
        return lbTF;
    }

    private PanTextField tgtTF;

    PanTextField getTargetStakeTF() {
        if (tgtTF == null) {
            tgtTF = w.cf
                    .createTitledField(
                            w,
                            10,
                            Util.x("Target Stake"),
                            Util.x("Target Stake (automatic mode only), ignored if 0."),
                            new DollarConverter()
                                    .int2str(ConfigDft.DEFAULT_TARGET_STAKE),
                            "tgtstk");
        }
        return tgtTF;
    }

    private PanTextField incrTF;

    PanTextField getIncrTF() {
        if (incrTF == null) {
            incrTF = w.cf.createTitledField(w, 10, Util.x("Increment"), Util
                    .x("Bet increment."), new DollarConverter()
                    .int2str(ConfigDft.DEFAULT_INITIAL_WAGER), "incr");
        }
        return incrTF;
    }

    private PanTextField stakeTF;

    protected PanTextField getStakeTF() {
        if (stakeTF == null) {
            stakeTF = w.cf.createTitledField(w, 10, Util.x("Stake"), Util
                    .x("Initial stake."), new DollarConverter()
                    .int2str(ConfigDft.DEFAULT_INITIAL_STAKE), "stake");
        }
        return stakeTF;
    }

    private JComboBox<String> countingSystemsSelect;

    JComboBox<String> getCountingSystemsSelect() {
        if (countingSystemsSelect == null) {
            countingSystemsSelect = w.cf.createGroundedComboBox(w,
                    Util.x("System"), Util.x("Select counting system"),
                    CountingSystems.DFT_COUNTING_SYSTEM_KEY, "cntgsys",
                    getCountingSystems().getKeys());
            countingSystemsSelect.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(final ActionEvent e) {
                    getCountingSystems().setCountingSystem(
                            countingSystemsSelect.getSelectedIndex());
                    BlackjackGame.countingSystem = getCountingSystems()
                            .getSelected();
                }

            });
        }
        return countingSystemsSelect;
    }

    private PanTextField bsTF;

    PanTextField getBetStrategyTF() {
        if (bsTF == null) {
            bsTF = w.cf
                    .createTitledField(
                            w,
                            10,
                            Util.x("Positive count large bet trigger"),
                            Util.x("When the count reaches this number, the large bet amount will be used. No action if 0."),
                            "10", "betstrategy");
        }
        return bsTF;
    }

    private PanTextField bsnTF;

    PanTextField getBetStrategyNegativeCountTF() {
        if (bsnTF == null) {
            bsnTF = w.cf
                    .createTitledField(
                            w,
                            10,
                            Util.x("Negative count bail trigger"),
                            Util.x("When the count reaches this number, shuffle (leave table).  No action if 0."),
                            "0", "betstrategy");
        }
        return bsnTF;
    }

    private PanTextField decksTF;

    PanTextField getDecksTF() {
        if (decksTF == null) {
            decksTF = w.cf.createTitledField(w, 10, Util.x("Decks"),
                    Util.x("Number of decks."), "8", "decks");
        }
        return decksTF;
    }

    private JPanel p;

    public Component getPanel() {
        if (p == null) {
            p = w.cf.createPanel(new BorderLayout());
            p.setName(Util.x("Setup"));
            JPanel np = w.cf.createPanel(new GridLayout(2, 1));
            JTabbedPane cpp = new JTabbedPane();
            FontManager.getInstance().register(cpp,
                    FontManager.FontType.boldArial);
            JPanel cp = w.cf.createPanel(new GridLayout(1, 2));
            cp.setName(Util.x("Basic Strategy"));
            cp.add(getBasicStrategyTA().getPanel());
            cp.add(getCountingSystemsTA().getPanel());
            cpp.add(getRulesConfig().getPanel());
            cpp.add(cp);
            cpp.add(getStackedDeckPanel().getPanel());
            p.add(BorderLayout.NORTH, np);
            p.add(BorderLayout.CENTER, cpp);
        }
        return p;
    }

    private RulesConfig rc;

    private RulesConfig getRulesConfig() {
        if (rc == null) {
            rc = new RulesConfig(this);
        }
        return rc;
    }

    private JCheckBox dasCB;

    JCheckBox getDasCB() {
        if (dasCB == null) {
            dasCB = w.cf.createGroundedCheckBox(w,
                    Util.x("Double after split"),
                    Util.x("Double after split allowed"), true, "das");
        }
        return dasCB;
    }

    private JCheckBox lsaCB;

    JCheckBox getLsaCB() {
        if (lsaCB == null) {
            lsaCB = w.cf.createGroundedCheckBox(w, Util.x("Surrender"), Util
                    .x("Late (after check for blackjack) surrender allowed"),
                    new ConfigDft().isLateSurrenderAllowed(), "lsa");
        }
        return lsaCB;
    }

    @Override
    public boolean isDoubleAfterSplitAllowed() {
        return getDasCB().isSelected();
    }

    @Override
    public boolean isLateSurrenderAllowed() {
        return getLsaCB().isSelected();
    }

    private JCheckBox blackjack6to5;

    JCheckBox getBlackjack6to5() {
        if (blackjack6to5 == null) {
            blackjack6to5 = w.cf.createGroundedCheckBox(w,
                    Util.x("Blackjack pays 6 to 5"),
                    Util.x("Blackjack pays 6 to 5 instead of 3 to 2"),
                    new ConfigDft().isBlackjack6to5(), "bj65");
        }
        return blackjack6to5;
    }

    private JCheckBox hitSoft17CB;

    JCheckBox getHitSoft17CB() {
        if (hitSoft17CB == null) {
            hitSoft17CB = w.cf.createGroundedCheckBox(w,
                    Util.x("Dealer hits soft 17"),
                    Util.x("Dealer must hit soft 17"),
                    new ConfigDft().isDealerHitSoft17(), "hs17");
        }
        return hitSoft17CB;
    }

    private PanCheckBox europeanCB;

    PanCheckBox getEuropeanCB() {
        if (europeanCB == null) {
            europeanCB = new PanCheckBox(w, "European Style", "Dealer Peek",
                    false, "eurostyle");
        }
        return europeanCB;
    }

    @Override
    public boolean isEuropeanStyle() {
        return getEuropeanCB().isSelected();
    }

    @Override
    public boolean isDealerHitSoft17() {
        return getHitSoft17CB().isSelected();
    }

    @Override
    public boolean isBlackjack6to5() {
        return getBlackjack6to5().isSelected();
    }

    private JCheckBox fastDealCB;

    JCheckBox getFastDealCB() {
        if (fastDealCB == null) {
            fastDealCB = w.cf.createGroundedCheckBox(w, Util.x("Fast deal."),
                    Util.x("Deal automatically, if no mistakes are made."),
                    new ConfigDft().isFastDeal(), "fastDeal");
        }
        return fastDealCB;
    }

    @Override
    public boolean isFastDeal() {
        return getFastDealCB().isSelected();
    }

    private JCheckBox basicStragegyVariationsOnlyCB;

    JCheckBox getBasicStrategyVariationsOnlyCB() {
        if (basicStragegyVariationsOnlyCB == null) {
            basicStragegyVariationsOnlyCB = w.cf
                    .createGroundedCheckBox(
                            w,
                            Util.x("Variations."),
                            Util.x("Skip scenarios where there are no variations in the basic strategy"),
                            new ConfigDft().isBasicStrategyVariationsOnly(),
                            "bsvo");
        }
        return basicStragegyVariationsOnlyCB;
    }

    @Override
    public boolean isBasicStrategyVariationsOnly() {
        return getBasicStrategyVariationsOnlyCB().isSelected();
    }

    private JCheckBox showCountCB;

    JCheckBox getShowCountCB() {
        if (showCountCB == null) {
            showCountCB = w.cf
                    .createGroundedCheckBox(
                            w,
                            Util.x("show count"),
                            Util.x("Leave this unchecked when playing, and you can check it to verify periodically during play."),
                            new ConfigDft().isShowCount(), "rsa");
        }
        return showCountCB;
    }

    private JCheckBox rsaCB;

    JCheckBox getRsaCB() {
        if (rsaCB == null) {
            rsaCB = w.cf.createGroundedCheckBox(w, Util.x("Re-split aces"),
                    Util.x("Re-split aces allowed"),
                    new ConfigDft().isResplitAcesAllowed(), "rsa");
        }
        return rsaCB;
    }

    @Override
    public boolean isResplitAcesAllowed() {
        return getRsaCB().isSelected();
    }

    @Override
    public boolean isShowCount() {
        return getShowCountCB().isSelected();
    }

    @Override
    public void toggleShowCount() {
        getShowCountCB().setSelected(!getShowCountCB().isSelected());
    }

    private CountingSystems csyss;

    @Override
    public CountingSystems getCountingSystems() {
        if (csyss == null) {
            csyss = new CountingSystems(
                    Strings.stringLines(getCountingSystemsTA().getText()));
        }
        return csyss;
    }

    private StackedDeckPanel sdp;

    private StackedDeckPanel getStackedDeckPanel() {
        if (sdp == null) {
            sdp = new StackedDeckPanel(this, w);
        }
        return sdp;
    }

    private TitledTextArea cs;

    private TitledTextArea getCountingSystemsTA() {
        if (cs == null) {
            String dft = "";
            try {
                dft = RezIO.loadTextFromResource(

                ConfigDft.DEFAULT_COUNTING_SYSTEMS_RSRC, this.getClass());
            } catch (IOException e) {
                Util.log(e);
            }
            cs = w.cf.createTitledTextArea(w, Util.x("Counting Systems"),
                    Util.x("Counting systems for Blackjack"), dft, "cs");
            if (!Strings.isPopulated(cs.getText())) {
                cs.setText(dft);
            }
        }
        return cs;
    }

    @Override
    public boolean isCountVeryPositive() {
        try {
            if (Strings.isPopulated(getBetStrategyTF().getText())) {
                int trigger = Integer.parseInt(getBetStrategyTF().getText());
                if (trigger == 0) {
                    return false;
                }
                if (BlackjackGame.countingSystem != null) {
                    return BlackjackGame.countingSystem.getCount() > trigger;
                }
            }
        } catch (final NumberFormatException ex) {
            Util.log(ex);
        }
        return false;
    }

    @Override
    public boolean isCountVeryNegative() {
        try {
            if (Strings.isPopulated(getBetStrategyNegativeCountTF().getText())) {
                int trigger = Integer.parseInt(getBetStrategyNegativeCountTF()
                        .getText());
                if (trigger == 0) {
                    return false;
                }
                if (BlackjackGame.countingSystem != null) {
                    return BlackjackGame.countingSystem.getCount() < -trigger;
                }
            }
        } catch (final NumberFormatException ex) {
            Util.log(ex);
        }
        return false;
    }

    @Override
    public String getStackedDeck() {
        return getStackedDeckPanel().getText();
    }

    @Override
    public String getWonMsg() {
        return "Won";
    }

    @Override
    public String getLostMsg() {
        return "Lost";
    }

    @Override
    public String getPushMsg() {
        return "Push";
    }

    @Override
    public String getBlackjackMsg() {
        return "Blackjack";
    }

    @Override
    public String getBustedMsg() {
        return "Busted";
    }

    @Override
    public String getHandNotActiveMsg() {
        return "Hand is not active.";
    }

    @Override
    public String getHandNotDealtMsg() {
        return "Hand has not been dealt yet.";
    }

    @Override
    public String getDoubleImpossibleMsg() {
        return "Double not possible here.";
    }

    @Override
    public String getHandActiveMsg() {
        return "Hand is still active";
    }

    @Override
    public String getShuffledMsg() {
        return "Shuffled";
    }

    @Override
    public String getPleaseSelectMsg() {
        return "Please select";
    }

    @Override
    public String getDealMsg() {
        return "Deal";
    }

    @Override
    public String getResetMsg() {
        return "Reset";
    }

    @Override
    public ScreenSizer getScreenSizer() {
        switch (FontManager.getInstance().getSize()) {
        case SMALL:
            return ScreenSizer.SMALL;
        case MEDIUM:
            return ScreenSizer.MEDIUM;
        case LARGE:
            return ScreenSizer.LARGE;
        default:
            return ScreenSizer.LARGE;
        }
    }
}
